home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-02-19 | 18.7 KB | 564 lines | [TEXT/CWIE] |
- /*
- File: Accessor.c
-
- Contains: Object Accessors
-
- Written by: Francis Stanbach, Greg Anderson
-
- Copyright: © 1992, 1994-1995 by Apple Computer, Inc., all rights reserved.
-
- <17> 2/8/95 ga
- */
-
- #include <AERegistry.h>
- #include <AppleEvents.h>
- #include <AEObjects.h>
- #include <AEPackObject.h>
- #include <AERegistry.h>
-
- #include "Exceptions.h"
- #include "MoreAEM.h"
- #include "Accessor.h"
- #include "MarkToken.h"
-
-
-
- #include <Threads.h>
-
-
- #if GENERATINGCFM
-
- #include <MixedMode.h>
-
- //
- // Make routine descriptors for our callbacks
- //
- static RoutineDescriptor gCompareCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLCompareProcInfo, TAccessor::CompareTokens);
- static RoutineDescriptor gCountCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLCountProcInfo, TAccessor::CountElements);
- static RoutineDescriptor gDisposeCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLDisposeTokenProcInfo, TAccessor::DisposeToken);
- static RoutineDescriptor gCreateMarkCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLGetMarkTokenProcInfo, TAccessor::CreateMark);
- static RoutineDescriptor gAddToMarkCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLMarkProcInfo, TAccessor::AddToMark);
- static RoutineDescriptor gAdjustMarksCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLAdjustMarksProcInfo, TAccessor::AdjustMarks);
- // static RoutineDescriptor gGetErrorDescCallbackRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLGetErrDescProcInfo, TAccessor::GetErrorDesc);
- static RoutineDescriptor gNullAccessorRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLAccessorProcInfo, TAccessor::NullAccessor);
- static RoutineDescriptor gListAccessorRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLAccessorProcInfo, TAccessor::ListAccessor);
- // static RoutineDescriptor gAliasTokenAccessorRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLAccessorProcInfo, TAccessor::AliasTokenAccessor);
- static RoutineDescriptor gWildCardAccessorRD = BUILD_ROUTINE_DESCRIPTOR(uppOSLAccessorProcInfo, TAccessor::WildCardAccessor);
-
- #endif
-
-
- #pragma segment Access
-
-
- TTokenDescriptor gNullContainer;
-
- //----------------------------------------------------------------------------------------
- // TAccessor::InstallAEHandlers:
- //
- // This method installs all of the callbacks required to support calls to AEResolve.
- //----------------------------------------------------------------------------------------
- #pragma segment Init
- void TAccessor::InstallAEHandlers()
- {
- //
- // Clear out the global error descriptor, just for good measure
- //
- // gErrorDescriptor.ClearDescriptor();
- gNullContainer.ClearDescriptor();
-
-
- #if GENERATINGCFM
- //
- // Install routine descriptors for all of our callbacks
- //
- FailErr(AESetObjectCallbacks( &gCompareCallbackRD,
- &gCountCallbackRD,
- &gDisposeCallbackRD,
- &gCreateMarkCallbackRD,
- &gAddToMarkCallbackRD,
- &gAdjustMarksCallbackRD,
- nil // &gGetErrorDescCallbackRD
- ));
-
- //
- // Install routine descriptors for our object accessors
- //
- FailErr(AEInstallObjectAccessor(typeWildCard, typeNull, &gNullAccessorRD, 0, false));
- FailErr(AEInstallObjectAccessor(typeWildCard, typeAEList, &gListAccessorRD, 0, false));
- // FailErr(AEInstallObjectAccessor(typeWildCard, 'alis', &gAliasTokenAccessorRD, 0, false));
- FailErr(AEInstallObjectAccessor(typeWildCard, typeWildCard, &gWildCardAccessorRD, 0, false));
-
- #else
- //
- // Install function pointers to all of our callbacks
- //
- FailErr(AESetObjectCallbacks( (OSLCompareProcPtr) &TAccessor::CompareTokens,
- (OSLCountProcPtr) &TAccessor::CountElements,
- (OSLDisposeTokenProcPtr) &TAccessor::DisposeToken,
- (OSLGetMarkTokenProcPtr) &TAccessor::CreateMark,
- (OSLMarkProcPtr) &TAccessor::AddToMark,
- (OSLAdjustMarksProcPtr) &TAccessor::AdjustMarks,
- nil // gGetErrorDescCallback
- ));
-
- //
- // Install function pointers to our object accessors
- //
- FailErr(AEInstallObjectAccessor(typeWildCard, typeNull, (OSLAccessorProcPtr) &TAccessor::NullAccessor, 0, false));
- FailErr(AEInstallObjectAccessor(typeWildCard, typeAEList, (OSLAccessorProcPtr) &TAccessor::ListAccessor, 0, false));
- // FailErr(AEInstallObjectAccessor(typeWildCard, 'alis', (OSLAccessorProcPtr) &TAccessor::AliasTokenAccessor, 0, false));
- FailErr(AEInstallObjectAccessor(typeWildCard, typeWildCard, (OSLAccessorProcPtr) &TAccessor::WildCardAccessor, 0, false));
- #endif
-
-
- //
- // Declare that we know how to deal with marking and whose clauses
- //
- TDescriptor::SetCallbackFlags(kAEIDoMarking + kAEIDoWhose);
- } // TAccessor::InstallAEHandlers
-
-
- //----------------------------------------------------------------------------------------
- // TAccessor::CompareTokens:
- //
- // CompareTokens is called to resolve 'whose' clauses. One parameter of the callback,
- // 'theObject', is always a token that the object support library asked us to generate.
- // The other parameter of the comparison, descOrObject, could be either a literal
- // descriptor (such as a string or an integer) or an object specifier.
- //
- // Abstract Scriptable Object has a framework for dealing with object specifiers in comparison tokens.
- // It will automatically call AEResolve to resolve the 'descOrObject' parameter if
- // an object specifier is passed in. It then tries to compare the best data type
- // of 'theObject' with the object from 'descOrObject'; if 'descOrObject' cannot provide
- // the best type of 'theObject', then it gets the best type of 'descOrObject' and
- // tries to do a coercion. See TAbstractScriptableObject::Compare
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::CompareTokens( DescType comparisonOperator,
- TTokenDescriptor& theObject,
- TDescriptor& descOrObject,
- Boolean& result )
- {
- OSErr err = noErr;
-
- result = false;
-
- Try
- {
- TAbstractScriptableObject* tokenToCompare = nil;
- DescType objectType = theObject.DescriptorType();
-
- //
- // We usually expect that the object's type will be typeTokenObject
- //
- if((objectType == typeTokenObject) || (objectType == typeTokenInHandle))
- {
- tokenToCompare = theObject.TokenObject();
-
- if(tokenToCompare != nil)
- {
- result = tokenToCompare->Compare(TAETransaction(), comparisonOperator, descOrObject);
- }
- }
- //
- // In strange cases, the 'descOrObject' will be a token
- // but the 'theObject' will be a literal. Inside Macintosh
- // claims this will never happen, but it LIES.
- //
- else if((descOrObject.DescriptorType() == typeTokenObject) || (descOrObject.DescriptorType() == typeTokenInHandle))
- {
- tokenToCompare = ((TTokenDescriptor*)(&descOrObject))->TokenObject();
-
- if(tokenToCompare != nil)
- {
- result = tokenToCompare->Compare(TAETransaction(), ReverseComparisonOperator(comparisonOperator),theObject);
- }
- }
- //
- // If we don't get a token, assume it's raw data
- //
- else
- {
- result = theObject.Compare(comparisonOperator,descOrObject);
- }
-
- }
- Catch(err)
- {
- }
-
- return err;
- } // TAccessor::CompareTokens
-
-
- //----------------------------------------------------------------------------------------
- // TAccessor::CountElements:
- //
- // The CountElements callback is called by the object support library when handling
- // events such as 'whose' clauses. There is also a 'count' event which is called by
- // scripts that have count commands (e.g. "count desktop each file"). Both callbacks
- // do essentially the same thing, but we have to support them both.
- //
- // Note that 'containerToken' might be an AEList, so we need to iterate the elements
- // of the list with the 'ForEachToken' macro.
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::CountElements( DescType classToCount,
- DescType containerClass,
- TTokenDescriptor& containerToken,
- long& result )
- {
- TTokenDescriptor nullContainerDesc;
- long theCount = 0;
- OSErr err = noErr;
-
- Try
- {
- //
- // If the containerToken is a null descriptor, then create
- // a token for the null container and count the elements of it
- //
- if(containerToken.IsNullDescriptor())
- {
- nullContainerDesc = CreateNullContainerToken();
- FailErr( TAccessor::CountElements(classToCount, containerClass, nullContainerDesc, theCount) );
- nullContainerDesc.DisposeToken();
- }
- //
- // Count the elements of each token in the containerToken
- //
- else
- {
- theCount = containerToken.TokenObject()->CountElements(TAETransaction(), classToCount);
- }
- }
- Catch(err)
- {
- nullContainerDesc.DisposeToken();
- }
-
- result = theCount;
-
- return err;
- } // TAccessor::CountElements
-
- //----------------------------------------------------------------------------------------
- // TAccessor::DisposeToken:
- //
- // The dispose token method is called every time the object support library or our
- // code calls AEDisposeToken. As a general rule, our dispose token callback will
- // never be passed a descriptor that was not generated by one of our accessor functions.
- // The exception to this rule is that the object support library will place our tokens
- // inside of AELists if it is processing a 'whose' clause, or resolving some other
- // object specifier that specifies multiple tokens (formRange, for example). If it
- // does so, it will pass the AEList to our dispose token callback; we then have to pull
- // all of the tokens out of it just to immediately delete them again. If we do not do
- // this, then tokens that own other objects in memory would never have a chance to clean
- // up the memory they use, and we would have a nasty memory leak.
- //
- // The 'marking' mechanism of the object support library could be used to avoid copying
- // our tokens into AELists, but we would have to take on the responsibility of dealing
- // with maintaining collections of tokens if we used marking.
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::DisposeToken(TTokenDescriptor& tokenDesc)
- {
- OSErr err = noErr;
-
- Try
- {
- DescType typeToDelete = tokenDesc.DescriptorType();
-
- //
- // Is this token derived from TTokenObject?
- //
- if((typeToDelete == typeTokenObject) || (typeToDelete == typeTokenInHandle))
- {
- TAbstractScriptableObject* token = tokenDesc.TokenObject();
- if(token != nil)
- {
- token->DisposeDesignator();
- }
-
- if(typeToDelete == typeTokenObject)
- tokenDesc.ClearDescriptor();
- else
- tokenDesc.Dispose();
- }
- //
- // Is this token an AEList?
- //
- else if(typeToDelete == typeAEList)
- {
- //
- // Dispose of each token inside the list in turn
- //
- //FOREACHTOKEN(&tokenDesc, tokenDescriptor)
- // {
- // tokenDescriptor.DisposeToken();
- // }
- //
- // Once we get rid of the contents of the list,
- // we must delete the list itself as well
- //
- //tokenDesc.Dispose();
- }
- //
- // Disposing a null descriptor? Do nothing
- //
- // If we don't recognize the token, then fail with errAEEventNotHandled.
- // The object support library will then try to dispose of it for us
- //
- else if(typeToDelete != typeNull)
- {
- FailErr(errAEEventNotHandled);
- }
- }
- Catch(err)
- {
- }
-
- return err;
- } // TAccessor::DisposeToken
-
- //----------------------------------------------------------------------------------------
- // TAccessor::CreateMark:
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::CreateMark( TTokenDescriptor& /*containerToken*/,
- DescType /*desiredClass*/,
- TTokenDescriptor* markTokenDesc )
- {
- TMarkToken* markToken;
- OSErr theErr = noErr;
-
- markTokenDesc->ClearDescriptor();
- NOREGISTER(markToken);
-
- Try
- {
- markToken = new TMarkToken(kAlwaysMakeCollection);
- markToken->IMarkToken();
-
- markTokenDesc->AdoptToken(markToken);
- }
- Catch(theErr)
- {
- if(markToken != nil)
- delete markToken;
- }
-
- return theErr;
- } // TAccessor::CreateMark
-
- //----------------------------------------------------------------------------------------
- // TAccessor::AddToMark:
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::AddToMark( TTokenDescriptor& tokenToAdd,
- TTokenDescriptor& markToken,
- long /*markCount*/ )
- {
- OSErr err = noErr;
-
- Try
- {
- markToken.TokenObject()->AdoptToken(tokenToAdd.TokenObject()->CloneDesignator(), kAlwaysMakeCollection);
- }
- Catch(err)
- {
- }
-
- return err;
- } // TAccessor::AddToMark
-
- //----------------------------------------------------------------------------------------
- // TAccessor::AdjustMarks:
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::AdjustMarks(long newStart,
- long newStop,
- TTokenDescriptor& markTokenDesc )
- {
- //
- // It's fairly reasonable to downcast to TMarkToken here, because
- // we trust the object support library to only give us mark tokens
- // that we generated with TAccessor::CreateMark. Still, we'll
- // do a membership test so as to not be completely evil.
- //
- TMarkToken* markToken = (TMarkToken*)markTokenDesc.TokenObject();
- if(markToken->DerivedFromOSLClass(TAETransaction(),cMarkToken))
- markToken->AdjustMarks(newStart, newStop);
-
- return noErr;
- } // TAccessor::AdjustMarks
-
- //----------------------------------------------------------------------------------------
- // TAccessor::NullAccessor:
- //
- // The null accessor is called whenever the containerToken is null; its only function
- // is to fill in the global container (the desktop) and call the wildcard accessor.
- // We could have just made the WildCard accessor recognize the null container, but
- // I preferred to do it this way since it simplified the creation and deletion of the
- // temporary null container token.
- //
- // A new null container token is created and disposed every time the null accessor
- // is called just to be consistant with our memory ownership rules and lifetime/scope
- // of tokens rules which involve always creating tokens when they are needed and
- // disposing them again when their life is over. I could have also made the dispose
- // token routine check for the null container token and not delete it; that would have
- // allowed me to create but a single null container token which could be reused each
- // time the null accessor was called. I opted to aviod the special checking, but there
- // is no reason why the code couldn't be optimized to do it.
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::NullAccessor( DescType desiredClass,
- TTokenDescriptor& /*containerToken*/,
- DescType containerClass,
- DescType keyForm,
- TDescriptor& keyData,
- TTokenDescriptor* token,
- long hRefCon )
- {
-
- OSErr err = noErr;
-
- Try
- {
- if(gNullContainer.IsNullDescriptor())
- gNullContainer = CreateNullContainerToken();
-
- FailErr( WildCardAccessor(desiredClass, gNullContainer, containerClass,
- keyForm, keyData, token, hRefCon) );
- }
- Catch(err)
- {
- }
-
- return err;
- } // TAccessor::NullAccessor
-
-
- //----------------------------------------------------------------------------------------
- // TAccessor::ListAccessor:
- //
- // Once again, the object support library might pass an AEList in as the
- // 'containerToken', so we iterate over each item in the list with the 'ForEachToken'
- // macro. If our accessor returns multiple objects (or if we call multiple accessors),
- // then we will also put the resulting tokens into an AEList and return it to the
- // object support library. Note that this accessor is never called if your application
- // supports marking.
- //
- // It begs the question: why doesn't the object support library handle this case
- // for us, huh?
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::ListAccessor( DescType desiredClass,
- TTokenDescriptor& containerToken,
- DescType containerClass,
- DescType keyForm,
- TDescriptor& keyData,
- TTokenDescriptor* resultToken,
- long /*hRefCon*/ )
- {
- TTokenDescriptor tokenDescriptor;
- OSErr err = noErr;
- resultToken->ClearDescriptor();
-
- //
- // If the containerToken is an empty list, we could fail
- // with the result 'errAEEmptyListContainer'.
- //
-
- Try
- {
- for(TDescriptorIterator iter(containerToken); iter.More(); iter.Next())
- {
- AECallObjectAccessor(desiredClass, iter.Current(), containerClass,
- keyForm, keyData, (AEDesc*) &tokenDescriptor);
-
- resultToken->AdoptToken(tokenDescriptor);
- tokenDescriptor.ClearDescriptor();
- }
- }
- Catch(err)
- {
- }
-
- //
- // It's a bit gross to do this, but currently,
- // access by name does not fail if no item with
- // the given name can be found. We must set
- // the error code here
- //
- if((err == noErr) && (resultToken->IsNullDescriptor()))
- {
- err = errAENoSuchObject;
- }
-
- return err;
- } // TAccessor::ListAccessor
-
-
- //----------------------------------------------------------------------------------------
- // TAccessor::WildCardAccessor:
- //
- // The wildcard accessor does nothing more than pass the access message to the
- // container that it was passed. TTokenObject::Access then calls through to the
- // appropriate method (AccessByIndex, AccessByName, or AccessByProperty) of the
- // container.
- //----------------------------------------------------------------------------------------
- pascal OSErr TAccessor::WildCardAccessor( DescType desiredClass,
- TTokenDescriptor& containerToken,
- DescType /*containerClass*/,
- DescType keyForm,
- TDescriptor& keyData,
- TTokenDescriptor* resultToken,
- long /*hRefCon*/ )
- {
- OSErr err = noErr;
- resultToken->ClearDescriptor();
-
- Try
- {
- TAbstractScriptableObject* result = nil;
-
- result = containerToken.TokenObject()->Access(TAETransaction(),desiredClass,keyForm,keyData);
- resultToken->AdoptToken(result);
- }
- Catch(err)
- {
- //
- // If the keyForm is not recognized, then the error that should be returned is
- // errAEBadKeyForm. However, if the keyForm is formWhose, and the whose clause
- // is not handled by the token that it was sent to, then the Object Support
- // Library expects the error code to be errAEEventNotHandled. We special-case
- // this condition right here, but we could also do it in TAbstractScriptableObject::Access.
- //
- if((err == errAEBadKeyForm) && (keyForm == formWhose))
- {
- err = errAEEventNotHandled;
- }
-
- }
-
- //
- // It's a bit gross to do this, but currently,
- // access by name does not fail if no item with
- // the given name can be found. We must set
- // the error code here.
- //
- // ••• Question: can we insure that Access will
- // always fail if nothing is returned, and skag this code?
- //
- if((err == noErr) && (resultToken->IsNullDescriptor()))
- {
- ASSERTPRINT(false, ("WildCardAccessor Result is typeNull but error not set"));
- err = errAENoSuchObject;
- }
-
-
- //
- // Give other threads time before we actually return to OSL
- //
- YieldToAnyThread();
-
-
- return err;
- } // TAccessor::WildCardAccessor
-
-
-